/*!
 * Basic Extension JavaScript library v1.0
 * License: MIT (http://www.opensource.org/licenses/mit-license.php)
 */
Object.clone = function (obj) {
    var o;
    if (typeof obj == "object") {
        if (obj === null) {
            o = null;
        } else {
            if (obj instanceof Array) {
                o = [];
                for (var i = 0, len = obj.length; i < len; i++) {
                    o.push(Object.clone(obj[i]));
                }
            } else {
                o = {};
                for (var j in obj) {
                    o[j] = Object.clone(obj[j]);
                }
            }
        }
    } else {
        o = obj;
    }
    return o;
};

/********************************************************************************
 *								  扩展Math静态方法
 *******************************************************************************/
/**
 * 求平均
 */
Math.avg = function(){
	var sum = Math.sum.apply(null, arguments);
	var result = sum / arguments.length;
	return result;
};

/**
 * 求和
 */
Math.sum = function(){
	var result = 0;
	for (var i=0;i<arguments.length;i++) {
		result += arguments[i];
	}
	return result;
};

/********************************************************************************
 *								  扩展字符串对象
 *******************************************************************************/
/**
 * 删除左右两端的空格
 */
String.prototype.trim = function() {
	return this.replace(/(^\s*)|(\s*$)/g, "");
};

/**
 * 删除左边的空格
 */
String.prototype.ltrim = function() {
	return this.replace(/(^\s*)/g, "");
};

/**
 * 删除右边的空格
 */
String.prototype.rtrim = function() {
	return this.replace(/(\s*$)/g, "");
};

/**
 * 全部替换
 * @param findText 要替换的字符
 * @param replaceText 替换为
 * @returns
 */
String.prototype.replaceAll = function(findText, replaceText) {
	var regExp = new RegExp(findText, "g");
	return this.replace(regExp, replaceText);
};

/**
 * 转移字符串中的特殊字符为HTML
 * @param source 
 * @returns
 */
String.prototype.toHTML = function(){
	var source = '';
	source = this.replaceAll("&", "&amp;");
	source = source.replaceAll("<", "&lt;");
	source = source.replaceAll(">", "&gt;");
	source = source.replaceAll(" ", "&nbsp;");
	source = source.replaceAll("\n", "<br/>");
	return source;
};

/**
 * 判断字符串是否以str开头
 * @param str
 * @returns
 */
String.prototype.startWith = function(str){	 
  var reg=new RegExp("^"+str);	 
  return reg.test(this);		
};

/**
 * 判断字符串是否以str结尾
 * @param str
 * @returns
 */
String.prototype.endsWith = function(str){	 
  var reg=new RegExp(str+"$");	 
  return reg.test(this);		
};

/**
 * 判断字符串是否包含子串
 * @param substr 子串
 * @returns true：包含，false：不包含
 */
String.prototype.contains = function(substr){
	var replaced = this.replaceAll(substr, '');
	return this.length != replaced.length;
};

/**
 * 判断字符串是否包含特殊字符（ ' < > & ? # =）
 * @returns true：包含，false：不包含
 */
String.prototype.containsSpacialChar = function(){
	var specialRegex = /^[^"'<>&?#=‘’“”]*$/;
	if(specialRegex.test(this)) {
		return false;
	} else {
		return true;
	}
};


/**
 * 判断字符串是否为Email邮箱
 * @returns true:是，false:否
 */
String.prototype.isValidEmail = function(){
    if ((this.length > 128) || (this.length < 6)) {
        return false;
    }
    
    var r=/^[a-zA-Z0-9]+([._\-][a-zA-Z0-9]+)*@[a-zA-Z0-9]+([._\-][a-zA-Z0-9]+)*([.][a-zA-Z]+)+$/;
    if(!r.test(this)){
        return false;
    }
    return true;
};

/********************************************************************************
 *								  扩展数组对象
 *******************************************************************************/

/**
 * 在数组中指定位置插入元素
 * @param index 位置
 * @param value 元素
 * @returns
 */
Array.prototype.insertAt = function(index, value) {
	var part1 = this.slice(0, index);
	var part2 = this.slice(index);
	part1.push(value);
	return (part1.concat(part2));
};

/**
 * 移除数组中指定位置的元素
 * @param index 位置
 * @param value 元素
 * @returns
 */
Array.prototype.removeAt = function(index) {
	var part1 = this.slice(0, index);
	var part2 = this.slice(index);
	part1.pop();
	return (part1.concat(part2));
};

/**
 * 移除数组中的元素
 * @param b 要移除的元素
 * @returns
 */
//Array.prototype.remove = function(b) { 
//	var a = this.indexOf(b);
//	if (a >= 0) { 
//		this.splice(a, 1); 
//		return true; 
//	} else {
//		return false; 
//	}
//}; 

/**
 * 判断数组中是否存在某元素
 * @param obj 元素
 * @returns true：存在，false：不存在
 */
Array.prototype.contains = function(obj) { 
	return this.indexOf(obj) >= 0; 
};

/**
 * 转置二维数组
 * @returns 转置形成的新数组
 */
Array.prototype.transposition = function() {
	if (!(this[0] instanceof Array)) {
		throw new Error("array is not a double dimension matrix");
	}
	//定义一个数组存放转置后的数据
	var result=[];

	//把装置的数据放入一个数组result中
	//1、初始化，确定有多少行
	for(var i=0;i<this[0].length;i++){
		result[i]=[];
	}
	//2、先遍历旧数组，再动态添加数据
	for(var i=0;i<this.length;i++){
		
		for(var j=0;j<this[i].length;j++){
			//动态添加数据到result数组中
			result[j][i]=this[i][j];
		}
	}
	
	return result; 
};

/********************************************************************************
 *								  扩展数字对象
 *******************************************************************************/

/**
 * 将数值表示的毫秒转换为日期字符串
 * @param format 日期格式
 * @returns
 */
Number.prototype.toDate = function(format) {
	var d = new Date(this);
	return d.format(format);
};

/********************************************************************************
 *								  扩展日期对象
 *******************************************************************************/

/**
 * 按指定字符串格式化日期
 * @param fmt 日期格式 <p>年(y)可以用 1-4 个占位符，月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q)可以用1-2个占位符，毫秒(S)只能用1个占位符 </p>
 * @see <b>example:</b><br/> 
 * 		(new Date()).format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
 * 		(new Date()).format("yyyy-M-d h:m:s.S")	  ==> 2006-7-2 8:9:4.18
 * @returns string
 */
Date.prototype.format = function(fmt) {
	var o = {
		"M+" : this.getMonth()+1,				 //月份
		"d+" : this.getDate(),					//日
		"h+" : this.getHours(),				   //小时
		"m+" : this.getMinutes(),				 //分
		"s+" : this.getSeconds(),				 //秒
		"q+" : Math.floor((this.getMonth()+3)/3), //季度
		"S"  : this.getMilliseconds()			 //毫秒
	};
	
	if(/(y+)/.test(fmt)) 
		fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length)); 
		for(var k in o) {
			if(new RegExp("("+ k +")").test(fmt)) {
				fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length))); 
			}
		}
		return fmt; 
};

/**
 * 判断日期对象是否早于入参时间
 * @param milliseconds
 * @returns true: 早于, false: 不早于
 */
Date.prototype.earlier = function(milliseconds) {
	if (!milliseconds) {
		return false;
	}
	
	return this.getTime() < milliseconds;
};

/********************************************************************************
 *								  构造函数
 *******************************************************************************/
/*
 * MAP对象，实现MAP功能
 *
 * 接口：
 * size()     获取MAP元素个数
 * isEmpty()    判断MAP是否为空
 * clear()     删除MAP所有元素
 * put(key, value)   向MAP中增加元素（key, value) 
 * remove(key)    删除指定KEY的元素，成功返回True，失败返回False
 * get(key)    获取指定KEY的元素值VALUE，失败返回NULL
 * element(index)   获取指定索引的元素（使用element.key，element.value获取KEY和VALUE），失败返回NULL
 * containsKey(key)  判断MAP中是否含有指定KEY的元素
 * containsValue(value) 判断MAP中是否含有指定VALUE的元素
 * values()    获取MAP中所有VALUE的数组（ARRAY）
 * keys()     获取MAP中所有KEY的数组（ARRAY）
 *
 * 例子：
 * var map = new Map();
 *
 * map.put("key", "value");
 * var val = map.get("key")
 * ……
 *
 */
function Map() {
    this.elements = new Array();
 
    //获取MAP元素个数
    this.size = function() {
        return this.elements.length;
    };
 
    //判断MAP是否为空
    this.isEmpty = function() {
        return (this.elements.length < 1);
    };
 
    //删除MAP所有元素
    this.clear = function() {
        this.elements = new Array();
    };
 
    //向MAP中增加元素（key, value) 
    this.put = function(_key, _value) {
        this.elements.push( {
            key : _key,
            value : _value
        });
    };
 
    //删除指定KEY的元素，成功返回True，失败返回False
    this.remove = function(_key) {
        var bln = false;
        try {
            for (var i = 0; i < this.elements.length; i++) {
                if (this.elements[i].key == _key) {
                    this.elements.splice(i, 1);
                    return true;
                }
            }
        } catch (e) {
            bln = false;
        }
        return bln;
    };
 
    //获取指定KEY的元素值VALUE，失败返回NULL
    this.get = function(_key) {
        try {
            for (var i = 0; i < this.elements.length; i++) {
                if (this.elements[i].key == _key) {
                    return this.elements[i].value;
                }
            }
        } catch (e) {
            return null;
        }
    };
 
    //获取指定索引的元素（使用element.key，element.value获取KEY和VALUE），失败返回NULL
    this.element = function(_index) {
        if (_index < 0 || _index >= this.elements.length) {
            return null;
        }
        return this.elements[_index];
    };
 
    //判断MAP中是否含有指定KEY的元素
    this.containsKey = function(_key) {
        var bln = false;
        try {
            for (var i = 0; i < this.elements.length; i++) {
                if (this.elements[i].key == _key) {
                    bln = true;
                }
            }
        } catch (e) {
            bln = false;
        }
        return bln;
    };
 
    //判断MAP中是否含有指定VALUE的元素
    this.containsValue = function(_value) {
        var bln = false;
        try {
            for (var i = 0; i < this.elements.length; i++) {
                if (this.elements[i].value == _value) {
                    bln = true;
                }
            }
        } catch (e) {
            bln = false;
        }
        return bln;
    };
 
    //获取MAP中所有VALUE的数组（ARRAY）
    this.values = function() {
        var arr = new Array();
        for (var i = 0; i < this.elements.length; i++) {
            arr.push(this.elements[i].value);
        }
        return arr;
    };
 
    //获取MAP中所有KEY的数组（ARRAY）
    this.keys = function() {
        var arr = new Array();
        for (var i = 0; i < this.elements.length; i++) {
            arr.push(this.elements[i].key);
        }
        return arr;
    };
};


/********************************************************************************
 *								  全局对象
 *******************************************************************************/
var Message = {
	TYPE : {
		INFO : "info",
		CONFIRM : "confirm",
		SUCCESS : "success",
		ERROR : "error"
	},
	info : function(title, message, fn) {
		return this.create(this.TYPE.INFO, false, title, message, fn);
	},
	confirm : function(title, message, fn1, fn2) {
		return this.create(this.TYPE.CONFIRM, true, title, message, fn1, fn2);
	},
	success : function(title, message, fn) {
		return this.create(this.TYPE.SUCCESS, false, title, message, fn);
	},
	error : function(title, message, fn) {
		return this.create(this.TYPE.ERROR, false, title, message, fn);
	},
	create : function(type, showButton, title, message, fn1, fn2) {
		if (!message) {
			return;
		}
		var headerHtml = $('<h4 class="modal-title"></h4>').html(title);
		var bodyHtml = $('<div></div>').addClass("modal-message-" + type).html(message);
		var modalBackdrop = $('<div class="modal-backdrop fade in" style="height: 100%"></div>');
		var modalDialog = $('<div class="modal-message modal-dialog" tabindex="-1"></div>');
		var modalContent = $('<div class="modal-content"></div>');
		var modalHeader = $('<div class="modal-header"></div>').append(headerHtml);
		var modalBody = $('<div class="modal-body"></div>').append(bodyHtml);
		var modalFooter = $('<div class="modal-footer"></div>');
		
		modalContent.append(modalHeader).append(modalBody).append(modalFooter).appendTo(modalDialog);
		
		var hide = function() {
			modalDialog.remove();
			modalBackdrop.remove();
		};

		var enterButton = $("<button class='btn btn-primary'>确定</button>").click(function() {
			if (fn1) {
				var flag = fn1();
				if (flag != false) {
					hide();
				}
			} else {
				hide();
			}
		});
		
		var cancelButton = $("<button class='btn btn-default'>取消</button>").click(function() {
			fn2 && (fn2() || hide());
			fn2 || hide();
		});
		
		modalFooter.append(enterButton);
		showButton && modalFooter.append(cancelButton);

		if ($(".modal-message:visible").length == 0) {
			modalBackdrop.appendTo("body");
			modalDialog.appendTo("body");
		}
		
		enterButton.focus();
	}
};